import { writeFile, readFile } from 'fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import { getDocDetail, getRepoDocs, getAllRepos } from './api.mjs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export async function writeContent(filePath, content, callback = () => {}) {
  try {
    await writeFile(filePath, content);
  } catch (err) {
    callback(err);
    console.log('写入文件出错');
    console.log('写入路径：', filePath);
    console.log('请确保路径存在');
  }
}

export async function readCache(path) {
  try {
    return JSON.parse(await readFile(path));
  } catch (err) {
    return [];
  }
}

/**
 * 导出知识库下的所有文档
 * @param {function} syncDoc 导出单篇语雀文档的方法
 * @param {string} login 语雀用户login
 * @param {string} repo 知识库slug
 * @param {string} cacheDir 缓存目录
 * @param {string} contentOutputDir 内容输出目录
 */
export async function syncDocs(
  syncDoc,
  login,
  repo,
  cacheDir,
  contentOutputDir
) {
  console.time(`同步知识库${repo}耗时`);
  let successCount = 0;
  let failedDocs = [];
  const namespace = `${login}/${repo}`;
  console.log(`正在获取知识库${namespace}的文档列表`);
  return getRepoDocs(namespace).then(
    async (res) => {
      const docs = res.data.map(
        ({ id, title, slug, created_at, updated_at }) => {
          return [id, updated_at, slug, title, created_at];
        }
      );
      // 设置缓存目录与路径
      cacheDir = cacheDir || __dirname;
      const cachePath = `${cacheDir}/${repo}-cache.json`;
      // 分析差异
      const { differences, docMap } = await analyseDiff(cachePath, docs);
      console.log('需要同步的文档数：', differences.length);
      if (differences.length == 0) {
        console.log('所有文档已同步');
        return;
      }

      // 下载对应的文档
      for (let { id, updated_at, title, slug } of differences) {
        console.log(`正在同步文档 ${title}`);
        try {
          await syncDoc(
            namespace,
            slug,
            `${title}-${repo}-${slug}`,
            contentOutputDir
          );
          // 下载成功后修改缓存
          docMap.set(id, updated_at);
          successCount++;
        } catch (err) {
          failedDocs.push([id, title, slug]);
          console.log(`文档 ${title} 同步失败！！！`);
          console.log('错误如下：******************');
          console.log(err);
        }
      }
      // 缓存哈希表
      const cache = Array.from(docMap);
      console.log('正在更新缓存');
      // 文档全部下载完成，最后更新缓存文件
      await writeContent(cachePath, JSON.stringify(cache));
      console.log(`${repo}知识库文档同步完成`);
      console.log(
        `!!!!同步失败的文档数：${failedDocs.length}，总文档数：${docs.length}，需要同步的文档数：${differences.length}`
      );
      console.log(failedDocs);
      console.timeEnd(`同步知识库${repo}耗时`);
    },
    (err) => {
      console.log('error... 请求文档列表出错');
      console.log(err);
    }
  );
}
/**
 * 同步单个语雀文档
 * @param {string} namespace 语雀文档的命名空间 login/repo
 * @param {string} slug 文章slug，具体见网页版语雀文档链接最后一部分
 * @param {string} filename 文章标题，用于输出文件的名称
 * @param {string} contentOutputDir 输出目录
 */
export async function syncDoc(namespace, slug, filename, contentOutputDir) {
  filename = getValidFileName(filename);
  const res = await getDocDetail(namespace, slug);
  // 内容输出路径，没有配置默认根目录下的content文件夹
  let output = contentOutputDir || `${__dirname}/content`;
  // 文件命名采取标题-slug形式
  output = `${output}/${filename}.md`;
  await writeContent(output, res.data.body);
}
/**
 * 分析本地与云端文档差异并返回差异数组与本地缓存哈希对象
 * @param {string} cachePath 缓存路径
 * @param {Array} docs [id,updated_at,slug,title]
 * @returns differences:[{id,updated_at,slug,title}],docMap:Map
 */
export async function analyseDiff(cachePath, docs) {
  // 读取之前的缓存文件
  let oldCache = await readCache(cachePath);
  // 构建哈希表
  let docMap = new Map();
  for (let [id, updated_at] of oldCache) {
    docMap.set(id, updated_at);
  }
  oldCache = null;
  const differences = [];
  console.log('正在分析差异...');
  // 比较新的缓存较旧缓存有哪些差异
  for (let [id, updated_at, slug, title] of docs) {
    if (!docMap.has(id) || docMap.get(id) != updated_at)
      differences.push({ id, updated_at, slug, title });
  }
  return { differences, docMap };
}

/**
 * 导出所有知识库下的文档
 * @param {string} login 语雀用户login
 * @param {string} cacheDir 缓存目录
 * @param {string} contentOutputDir 内容输出目录
 */
export function syncAllReposDocs(login, cacheDir, contentOutputDir) {
  console.log('正在获取知识库列表');
  getAllRepos().then(
    async (res) => {
      for (let { slug, name } of res.data) {
        console.log(`-------开始同步知识库${name}的文档`);
        try {
          await syncDocs(syncDoc, login, slug, cacheDir, contentOutputDir);
        } catch (err) {
          console.log(`!!!同步知识库${name}的文档失败!!!`);
        }
      }
    },
    (err) => {
      console.log('获取所有知识库失败');
      console.log(err);
    }
  );
}

/**
 * 将文件名中的非法字符替换为_
 * @param {string} filename 文件名称
 * @returns string
 */
export function getValidFileName(filename) {
  const validFileName = filename.replace(/[<>:"\/\\|?*]/g, '_'); // 替换违规字符为下划线
  return validFileName;
}
